﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;

namespace EmbeddedSensorCloud.Core.Plugin
{
    public class PluginExistingException : Exception
    {
        public readonly string PluginName;
        public readonly Version PluginVersion;

        public PluginExistingException(string pluginName, Version pluginVersion) : base()
        {
            this.PluginName = pluginName;
            this.PluginVersion = pluginVersion;
        }

        public override string ToString()
        {
            return string.Format("'{0}' v{1} already exists.", this.PluginName, this.PluginVersion);
        }
    }

    public class PluginLoadException : Exception
    {
        public PluginLoadException(string message) : base(message) { }

        public override string ToString()
        {
            return string.Format("Plugin loading failed:{0}   * {1} *", Environment.NewLine, base.Message);
        }
    }

    public abstract class PluginCreationException : Exception
    {
        public readonly string Path;
        public readonly string Name;
        public readonly Version Version;

        public PluginCreationException(string message, Exception inner, string path, string pluginName, Version pluginVersion)
            : base(message, inner)
        {
            this.Path = path;
            this.Name = pluginName;
            this.Version = pluginVersion;
        }

        public override string ToString()
        {
 	         return string.Format("Plugin creation at '{0}' failed:{1}   * {2} *", this.Path, Environment.NewLine, base.Message);
        }
    }

    public class PluginActivationException : PluginCreationException
    {
        private readonly Type pluginType;

        public PluginActivationException(string message, Exception inner, string path, string pluginName, Version pluginVersion, Type pluginType)
            : base(message, inner, path, pluginName, pluginVersion)
        {
            this.pluginType = pluginType;
        }

        public override string ToString()
        {
            StringBuilder s = new StringBuilder();
            s.AppendFormat("Activation of plugin '{0}' {1} at {2} failed:{3}   * {4} *{5}", 
                base.Name, 
                base.Version, 
                base.Path,
                Environment.NewLine,
                base.InnerException.Message,
                Environment.NewLine);

            var ctors = pluginType.GetConstructors();
            for (int i = 0; i < ctors.Length; i++)
            {
                string argumentLine = String.Join(", ", ctors[i].GetParameters().Select(P => P.Name + ":" + P.ParameterType.Name));
                string accessModifierString = ctors[i].IsPublic ? "+" : "-";
                s.AppendFormat("   {0} {1} ({2})", accessModifierString, pluginType.Name, argumentLine);

                if (i + 1 < ctors.Length)
                {
                    s.AppendLine();
                }
            }

            return s.ToString();
        }
    }

    public class PluginInitializationException : PluginCreationException
    {
        public PluginInitializationException(string message, Exception inner, string path, string pluginName, Version pluginVersion)
            : base(message, inner, path, pluginName, pluginVersion)
        {            
        }

        public override string ToString()
        {
            return string.Format("Initialization of plugin '{0}' {1} at '{2}' failed:{3}   * {4} *", 
                this.Name, 
                this.Version,
                this.Path,
                Environment.NewLine,
                base.InnerException.Message);
        }
    }
}
